// KCPTestClient project main.go
package main

import (
	"encoding/binary"
	"fmt"
	"net"
	"sync/atomic"
	"time"

	"github.com/xtaci/kcp-go"
)

const (
	SEND_INTERVAL  = 100
	SERVER_ADDRESS = "122.11.58.160:5555"
)

var kcpCntTotal, kcpSumLatency, tcpCntTotal, tcpSumLatency uint64

func handleKCPConn(kcpCli *kcp.UDPSession) {
	rdLen := 0
	rdBuff := make([]byte, 1024)
	var nowMS uint64
	for {
		n, err := kcpCli.Read(rdBuff[rdLen:])
		if err != nil {
			panic(err)
		} else {
			nowMS = uint64(time.Now().UnixNano() / 1000000)
			dataLen := n + rdLen
			for i := 0; i < dataLen/8; i++ {
				startIdx := i * 8
				endIdx := startIdx + 8
				sendTime := binary.LittleEndian.Uint64(rdBuff[startIdx:endIdx])
				latency := nowMS - sendTime
				atomic.AddUint64(&kcpSumLatency, latency)
				atomic.AddUint64(&kcpCntTotal, 1)
				AddChartData("kcp", uint32(latency))
			}
			rdLen = dataLen % 8
			if rdLen > 0 {
				tailIdx := dataLen - dataLen%8
				copy(rdBuff, rdBuff[tailIdx:])
			}
		}
	}
}

func handleTCPConn(kcpCli net.Conn) {
	rdLen := 0
	rdBuff := make([]byte, 1024)
	var nowMS uint64
	for {
		n, err := kcpCli.Read(rdBuff[rdLen:])
		if err != nil {
			panic(err)
		} else {
			nowMS = uint64(time.Now().UnixNano() / 1000000)
			dataLen := n + rdLen
			for i := 0; i < dataLen/8; i++ {
				startIdx := i * 8
				endIdx := startIdx + 8
				sendTime := binary.LittleEndian.Uint64(rdBuff[startIdx:endIdx])
				latency := nowMS - sendTime
				atomic.AddUint64(&tcpSumLatency, latency)
				atomic.AddUint64(&tcpCntTotal, 1)
				AddChartData("tcp", uint32(latency))
			}
			rdLen = dataLen % 8
			if rdLen > 0 {
				tailIdx := dataLen - dataLen%8
				copy(rdBuff, rdBuff[tailIdx:])
			}
		}
	}
}

func dialKCPServer() {
	var (
		// 每10毫秒发送一个测试包
		timeTicker = time.NewTicker(time.Millisecond * SEND_INTERVAL)
	)
	//连接KCPServer
	kcpCli, err := kcp.DialWithOptions(SERVER_ADDRESS, nil, 10, 3)
	if err != nil {
		panic(err)
	}
	kcpCli.SetWriteDelay(false)
	kcpCli.SetStreamMode(false)
	kcpCli.SetDSCP(46)
	go handleKCPConn(kcpCli)

	var nowMS uint64
	convBuff := make([]byte, 8)
	for {
		select {
		case <-timeTicker.C:
			nowMS = uint64(time.Now().UnixNano() / 1000000)
			binary.LittleEndian.PutUint64(convBuff, nowMS)
			kcpCli.Write(convBuff)
		}
	}
}

func dialTCPServer() {

	var (
		// 每10毫秒发送一个测试包
		timeTicker = time.NewTicker(time.Millisecond * SEND_INTERVAL)
	)
	//连接KCPServer
	cli, err := net.Dial("tcp", SERVER_ADDRESS)
	if err != nil {
		panic(err)
	}
	go handleTCPConn(cli)

	var nowMS uint64
	convBuff := make([]byte, 8)
	for {
		select {
		case <-timeTicker.C:
			nowMS = uint64(time.Now().UnixNano() / 1000000)
			binary.LittleEndian.PutUint64(convBuff, nowMS)
			cli.Write(convBuff)
		}
	}
}

func main() {
	fmt.Println("Hello World!")
	go ListenAndServe(":8000")
	go dialKCPServer()
	go dialTCPServer()
	var (
		// 每10秒打印一次统计数据
		timeTicker = time.NewTicker(time.Second * 10)
	)

	for {
		select {
		case <-timeTicker.C:
			tmpCnt := atomic.SwapUint64(&kcpCntTotal, 0)
			tmpLatency := atomic.SwapUint64(&kcpSumLatency, 0)
			if tmpCnt > 0 {
				fmt.Println("KCP packet count:", tmpCnt, " avg latency:", tmpLatency/tmpCnt, "(ms)")
			}

			tmpCnt = atomic.SwapUint64(&tcpCntTotal, 0)
			tmpLatency = atomic.SwapUint64(&tcpSumLatency, 0)
			if tmpCnt > 0 {
				fmt.Println("TCP packet count:", tmpCnt, " avg latency:", tmpLatency/tmpCnt, "(ms)")
			}
		}
	}
	fmt.Println("KCPTestClient is stoped!")
}
